#include "StdAfx.h"
#include "TextRender.h"

#include "DrawUtil.h"

CTextRender::CTextRender(void)
{
    memset(&m_Bmp, 0, sizeof(m_Bmp));

    m_hBufferDC = NULL;
    m_hBufferBmp = NULL;
}

CTextRender::~CTextRender(void)
{
    DestroyBuffer();
}

int CTextRender::Render(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat)
{
    return Render(hDC, lpString, nCount, lpRect, uFormat, 255);
}

int CTextRender::Render(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, BYTE byTextAlpha)
{
    LONG nWidth = lpRect->right - lpRect->left;
    LONG nHeight = lpRect->bottom - lpRect->top;

    // Prepare
    if(!EnsureBuffer(nWidth, nHeight))
        return 0;

    if(!PrepareRender(nWidth, nHeight))
        return 0;

    // 
    int nResult = 0;
    BOOL bResult = FALSE;
    HGDIOBJ hOldObj = NULL;
    HGDIOBJ hBufferOldObj = NULL;
    do 
    {
        hOldObj = ::SelectObject(hDC, m_hBufferBmp);
        if(hOldObj == NULL)
            break;

        RECT rcText = {0, 0, nWidth, nHeight};
        nResult = ::DrawText(hDC, lpString, nCount, &rcText, uFormat);
        if(nResult == 0)
            break;

        BYTE byAlpha, byRed, byGreen, byBlue;
        UINT uTemp = 0;
        UINT* uBits = (UINT*)m_Bmp.bmBits;
        LONG nCount = m_Bmp.bmWidth * m_Bmp.bmHeight;
        for(LONG i=0; i<nCount; ++ i)
        {
            UINT& pixel = uBits[i];
            if(pixel == 0x00FFFF00)
            {
                byBlue = (pixel & 0xFF);
                byGreen = ((pixel >> 8) & 0xFF);
                byRed = ((pixel >> 16) & 0xFF);

                byRed = (byTextAlpha * byRed + 127) / 255;
                byGreen = (byTextAlpha * byGreen + 127) / 255;
                byBlue = (byTextAlpha * byBlue + 127) / 255;

                // byAlpha = 0.2125f * byRed + 0.7154f * byGreen + 0.0721f * byBlue;
                byAlpha = byTextAlpha;

                pixel = byBlue | (byGreen << 8) | (byRed << 16) | (byAlpha << 24);
            }
        }

        ::SelectObject(hDC, hOldObj);
        hBufferOldObj = ::SelectObject(m_hBufferDC, m_hBufferBmp);
        if(hBufferOldObj == NULL)
            break;

        BLENDFUNCTION BlendFunc = {0};
        BlendFunc.BlendOp = AC_SRC_OVER;
        BlendFunc.SourceConstantAlpha = 255;
        BlendFunc.AlphaFormat = AC_SRC_ALPHA;
        BOOL bResult = AlphaBlend(hDC,
            lpRect->left, lpRect->top,
            nWidth, nHeight,
            m_hBufferDC,
            0, 0,
            nWidth, nHeight,
            BlendFunc);

    } while (FALSE);

    if(hOldObj != NULL)
        ::SelectObject(hDC, hOldObj);
    if(hBufferOldObj != NULL)
        ::SelectObject(m_hBufferDC, hBufferOldObj);

    return bResult ? nResult : 0;
}


//////////////////////////////////////////////////////////////////////////
BOOL CTextRender::EnsureBuffer(int nWidth, int nHeight)
{
    if(m_hBufferBmp != NULL && m_Bmp.bmWidth >= nWidth || m_Bmp.bmHeight >= nHeight)
        return TRUE;

    if(m_hBufferBmp != NULL)
    {
        DrawUtil::DeleteImage(*(XIMAGE*)&m_hBufferBmp);
        m_hBufferBmp = NULL;
    }

    if(m_hBufferDC == NULL)
    {
        m_hBufferDC = ::CreateCompatibleDC(NULL);
    }

    m_hBufferBmp = (HBITMAP)DrawUtil::CreateTransparentImage(nWidth, nHeight);
    BOOL bValid = (m_hBufferBmp != NULL);
    if(bValid)
    {
        ::GetObject(m_hBufferBmp, sizeof(m_Bmp), &m_Bmp);
    }

    return (m_hBufferBmp != NULL);
}

BOOL CTextRender::PrepareRender(int nWidth, int nHeight)
{
    UINT* uBits = (UINT*)m_Bmp.bmBits;
    LONG nCount = m_Bmp.bmWidth * m_Bmp.bmHeight;
    if(uBits == 0 || nCount <= 0)
        return FALSE;

    memset(uBits, 0, m_Bmp.bmBitsPixel * nCount / 8);

    return TRUE;
}

void CTextRender::DestroyBuffer()
{
    if(m_hBufferDC != NULL)
    {
        ::DeleteDC(m_hBufferDC);
        m_hBufferDC = NULL;
    }

    if(m_hBufferBmp != NULL)
    {
        DrawUtil::DeleteImage(*(XIMAGE*)&m_hBufferBmp);
        m_hBufferBmp = NULL;
        memset(&m_Bmp, 0, sizeof(m_Bmp));
    }
}

